package net.xiaoboli.mgp;

import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.logging.Log;
import org.mybatis.generator.logging.LogFactory;

import java.util.*;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;

public class ControllerPlugin extends PluginAdapter {
    // 项目目录，一般为 src/main/java
    private String targetProject;

    // service包名，如：service.service
    private String servicePackage;

    // Controlle类包名，如：service.controller
    private String controllerPackage;

    // service接口名前缀
    private String servicePrefix;

    // service接口名后缀
    private String serviceSuffix;

    private String superServiceInterface;
    // dao接口基类
//    private String superDaoInterface;
    // controller类的父类
    private String superController;

    private String recordType;

    private String modelName;

    private boolean actionAdd, actionInfo, actionEdit, actionDel, actionList;
    private String actionRemarkAdd, actionRemarkInfo, actionRemarkEdit, actionRemarkDel, actionRemarkList;

    private FullyQualifiedJavaType model;

    private String serviceName;
    private String controllerName;

    private String resultInfoName;
    private String resultListName;

    private String resultR;
    private String resultL;

    private boolean isRequestBody;
    private boolean isRequestModel;
    private boolean isRequestQuery;

    private boolean pageHelperDisabled = false;

    private Set<String> ignoreFieldsToAddSet = new HashSet<>();
    private Set<String> ignoreFieldsToEditSet = new HashSet<>();
    private Set<String> setDateFieldsToAddSet = new HashSet<>();
    private Set<String> setDateFieldsToEditSet = new HashSet<>();
    private Log log;
    private String[] modelMethods = null;

    private String loadUpdateBodyUse(IntrospectedTable introspectedTable) {
        return loadConfig(introspectedTable, "updateBodyUse", "no");
    }

    private String loadConfig(IntrospectedTable introspectedTable, String name, String defaultValue) {
        String s = introspectedTable.getTableConfiguration().getProperty(name);
        if (StringUtils.isBlank(s)) {
            s = properties.getProperty(name, defaultValue);
        }
        return s;
    }

    @Override
    public void initialized(IntrospectedTable introspectedTable) {
        this.log = LogFactory.getLog(this.getClass());

        if (!introspectedTable.hasPrimaryKeyColumns()) {
            throw new RuntimeException("Generator table must include primary key");
        }

        //
        targetProject = properties.getProperty("targetProject", "src/main/java");

        //
        String controllerProject = introspectedTable.getTableConfiguration().getProperty("controllerProject");
        if (StringUtils.isNotBlank(controllerProject)) {
            targetProject = controllerProject;
        }

        //
        servicePackage = properties.getProperty("servicePackage", "system.service");
        String sp = introspectedTable.getTableConfiguration().getProperty("servicePackage");
        if (StringUtils.isNotBlank(sp)) {
            servicePackage = sp;
        }

        //
        controllerPackage = properties.getProperty("controllerPackage", "web.controller");
        String cp = introspectedTable.getTableConfiguration().getProperty("controllerPackage");
        if (StringUtils.isNotBlank(cp)) {
            controllerPackage = cp;
        }

        //
        servicePrefix = properties.getProperty("servicePrefix");
        servicePrefix = stringHasValue(servicePrefix) ? servicePrefix : "";
        serviceSuffix = properties.getProperty("serviceSuffix", "Service");
        serviceSuffix = stringHasValue(serviceSuffix) ? serviceSuffix : "";
        superServiceInterface = properties.getProperty("superServiceInterface");
        superController = properties.getProperty("superController");

        //
        recordType = introspectedTable.getBaseRecordType();
        modelName = recordType.substring(recordType.lastIndexOf(".") + 1);
        model = new FullyQualifiedJavaType(recordType);
        serviceName = PluginUtil.serviceName(introspectedTable, servicePackage, servicePrefix, serviceSuffix);
        controllerName = PluginUtil.controllerName(introspectedTable, controllerPackage);

        // dto
        boolean dtoEnabled = true;
        if ("no".equals(introspectedTable.getTableConfiguration().getProperty("dto"))) {
            dtoEnabled = false;
        }

        //
        String dtoPackage = properties.getProperty("dtoPackage");
        String dtoMethod = properties.getProperty("dtoMethod");
        if (dtoEnabled && StringUtils.isNotBlank(dtoPackage) && StringUtils.isNotBlank(dtoMethod)) {
            String[] items = dtoMethod.split(",");
            if (items.length != 4) {
                throw new RuntimeException("dtoMethod and dtoPackage property configuration invalid");
            }

            //
            modelMethods = new String[4];
            modelMethods[0] = items[0].replace("{model}", modelName);
            modelMethods[1] = items[1].replace("{model}", modelName);
            modelMethods[2] = items[2].replace("{model}", modelName);
            modelMethods[3] = items[3].replace("{model}", modelName);

            //
            modelMethods[0] = PluginUtil.packageName(introspectedTable, dtoPackage, modelMethods[0]);
            modelMethods[1] = PluginUtil.packageName(introspectedTable, dtoPackage, modelMethods[1]);
            modelMethods[2] = PluginUtil.packageName(introspectedTable, dtoPackage, modelMethods[2]);
            modelMethods[3] = PluginUtil.packageName(introspectedTable, dtoPackage, modelMethods[3]);

            //
            introspectedTable.setAttribute("dtoMethodAdd", modelMethods[0]);
            introspectedTable.setAttribute("dtoMethodEdit", modelMethods[1]);
            introspectedTable.setAttribute("dtoMethodQuery", modelMethods[2]);
            introspectedTable.setAttribute("dtoMethodResult", modelMethods[3]);

        }

    }

    @Override
    public boolean validate(List<String> warnings) {
        boolean valid = true;

        if (!stringHasValue(properties
                .getProperty("targetProject"))) { //$NON-NLS-1$
            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
                    "MapperConfigPlugin", //$NON-NLS-1$
                    "targetProject")); //$NON-NLS-1$
            valid = false;
        }

//        if (!stringHasValue(properties.getProperty("controllerPackage"))) { //$NON-NLS-1$
//            warnings.add(getString("ValidationError.18", //$NON-NLS-1$
//                    "MapperConfigPlugin", //$NON-NLS-1$
//                    "controllerPackage")); //$NON-NLS-1$
//            valid = false;
//        }

        //
        resultInfoName = properties.getProperty("resultInfo", "framework.vo.ResultInfo");
        resultListName = properties.getProperty("resultList", "framework.vo.ResultList");
        resultR = properties.getProperty("resultR", "framework.vo.R");
        resultL = properties.getProperty("resultL", "framework.vo.L");
        String requestModel = properties.getProperty("requestModel");
        this.isRequestBody = "RequestBody".equalsIgnoreCase(requestModel);
        this.isRequestModel = "ModelAttribute".equalsIgnoreCase(requestModel);
        this.isRequestQuery = (this.isRequestBody || this.isRequestModel) == false;

        String _actions = properties.getProperty("actions");
        if (!StringUtils.isEmpty(_actions)) {
            for (String n : _actions.split(",")) {
                //add,info,edit,del,list,search
                if ("add".equals(n)) actionAdd = true;
                if ("info".equals(n)) actionInfo = true;
                if ("edit".equals(n)) actionEdit = true;
                if ("del".equals(n)) actionDel = true;
                if ("list".equals(n)) actionList = true;
            }
        }

        String _remarks = properties.getProperty("actionRemarks");
        if (StringUtils.isEmpty(_remarks)) {
            //添加%s,查看%s,%s更新,删除%s,%s列表,检索%s
            actionRemarkAdd = "Add %s";
            actionRemarkInfo = "View %s";
            actionRemarkEdit = "Update %s";
            actionRemarkDel = "Delete %s";
            actionRemarkList = "List %s";
        } else {
            String[] remarks = _remarks.split(",");
            if (remarks.length != 5) {
                warnings.add("Error: actionRemarks member must equal 5,order add,info,edit,del,list");
                return false;
            }
            actionRemarkAdd = remarks[0];
            actionRemarkInfo = remarks[1];
            actionRemarkEdit = remarks[2];
            actionRemarkDel = remarks[3];
            actionRemarkList = remarks[4];
        }

        pageHelperDisabled = "0".equals(properties.getProperty("pageHelperEnable"));

//            <!--添加时不填充字段-->
//            <property name="ignoreFieldsToAdd" value="id,ctime"/>
//            <!--修改时不填充字段-->
//            <property name="ignoreFieldsToEdit" value="ctime"/>
//            <!--添加时间字段-->
//            <property name="setDateFieldsToAdd" value="ctime,utime,create_time,update_time"/>
//            <!--修改时间字段-->
//            <property name="setDateFieldsToEdit" value="utime,update_time"/>

        String ignoreFieldsToAdd = properties.getProperty("ignoreFieldsToAdd", "");
        String ignoreFieldsToEdit = properties.getProperty("ignoreFieldsToEdit", "");
        String setDateFieldsToAdd = properties.getProperty("setDateFieldsToAdd", "");
        String setDateFieldsToEdit = properties.getProperty("setDateFieldsToEdit", "");

        this.ignoreFieldsToAddSet.addAll(Arrays.asList(ignoreFieldsToAdd.split(",")));
        this.ignoreFieldsToEditSet.addAll(Arrays.asList(ignoreFieldsToEdit.split(",")));
        this.setDateFieldsToAddSet.addAll(Arrays.asList(setDateFieldsToAdd.split(",")));
        this.setDateFieldsToEditSet.addAll(Arrays.asList(setDateFieldsToEdit.split(",")));


        return valid;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

        List<GeneratedJavaFile> answer = new ArrayList<>();

        try {
            this.generateAdditionalJavaFiles(introspectedTable, answer);
        } catch (Exception exception) {
            exception.printStackTrace();
            throw exception;
        }

        return answer;
    }

    @SneakyThrows
    private void generateAdditionalJavaFiles(IntrospectedTable introspectedTable, List<GeneratedJavaFile> answer) {

        GeneratedJavaFile c = generateController(introspectedTable);

        //
        String controller = introspectedTable.getTableConfigurationProperty("controller");
        if ("no".equals(controller)) {
            log.warn(PluginUtil.canonicalPath(c) + " skip create because controller configured to no");
        } else if (PluginUtil.canWrite(c))
            answer.add(c);
        else
            log.warn(PluginUtil.canonicalPath(c) + " is exists, skip create, you can delete it and regenerate");

    }

    // 生成controller类
    private GeneratedJavaFile generateController(IntrospectedTable introspectedTable) {

        //init view model

        FullyQualifiedJavaType controller = new FullyQualifiedJavaType(controllerName);
        TopLevelClass clazz = new TopLevelClass(controller);
        //描述类的作用域修饰符
        clazz.setVisibility(JavaVisibility.PUBLIC);

        //导入实体
        clazz.addImportedType(model);

        //导入model
        if (modelMethods != null) {
            for (String s : modelMethods) {
                clazz.addImportedType(new FullyQualifiedJavaType(s));
            }
        }

        //添加@Controller注解，并引入相应的类
        //clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RestController"));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.*"));
        clazz.addAnnotation("@RestController");
        //添加@RequestMapping注解，并引入相应的类
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestMapping"));
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.GetMapping"));
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.PostMapping"));
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestBody"));
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.RequestParam"));
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.PathVariable"));
        //clazz.addAnnotation("@RequestMapping(\"/" + StringUtil.firstCharToLowCase(modelName) + "\")");
        clazz.addAnnotation("@RequestMapping(\"/" + PluginUtil.modelToPath(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()) + "\")");
        //添加@Api注解，并引入相应的类
//        clazz.addImportedType(new FullyQualifiedJavaType("io.swagger.annotations.Api"));
//        clazz.addImportedType(new FullyQualifiedJavaType("io.swagger.annotations.ApiParam"));
//        clazz.addImportedType(new FullyQualifiedJavaType("io.swagger.annotations.ApiOperation"));
        clazz.addImportedType(new FullyQualifiedJavaType("io.swagger.annotations.*"));
        clazz.addImportedType(new FullyQualifiedJavaType(resultInfoName));
        clazz.addImportedType(new FullyQualifiedJavaType(resultListName));
        clazz.addImportedType(new FullyQualifiedJavaType(resultR));
        clazz.addImportedType(new FullyQualifiedJavaType(resultL));

        if (!pageHelperDisabled) {
            clazz.addImportedType(new FullyQualifiedJavaType("com.github.pagehelper.PageInfo"));
            // 系统容器包
            clazz.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        }

        //引入注解
//        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.web.bind.annotation.*"));

//        String controllerSimpleName = controllerName.substring(controllerName.lastIndexOf(".") + 1);
//        clazz.addAnnotation("@Api(tags = \"" + controllerSimpleName + "\", description = \"" + controllerSimpleName + "\")");
        if (!StringUtils.isEmpty(introspectedTable.getRemarks()))
            clazz.addAnnotation("@Api(tags = \"" + introspectedTable.getRemarks() + "\")");
        else
            clazz.addAnnotation("@Api(tags = \"" + modelName + "\")");

        //引入controller的父类和model，并添加泛型
        if (stringHasValue(superController)) {
            clazz.addImportedType(superController);
            clazz.addImportedType(recordType);
            FullyQualifiedJavaType superInterface = new FullyQualifiedJavaType(superController + "<" + modelName + ">");
            clazz.addSuperInterface(superInterface);
        }

        //引入Service
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        clazz.addImportedType(service);

        //添加Service成员变量
        String serviceFieldName = PluginUtil.firstCharToLowCase(serviceName.substring(serviceName.lastIndexOf(".") + 1));
        Field daoField = new Field(serviceFieldName, new FullyQualifiedJavaType(serviceName));
        clazz.addImportedType(new FullyQualifiedJavaType(serviceName));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        //描述成员属性 的注解
        daoField.addAnnotation("@Autowired");
        //描述成员属性修饰符
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);

        //
        if (stringHasValue(superServiceInterface)) {
            //描述 方法名
            Method method = new Method("get" + serviceSuffix);
            //方法注解
            method.addAnnotation("@Override");
            String simpleSuperServiceName = superServiceInterface.substring(superServiceInterface.lastIndexOf(".") + 1);
            FullyQualifiedJavaType methodReturnType = new FullyQualifiedJavaType(simpleSuperServiceName + "<" + modelName + ">");

            //返回类型
            method.setReturnType(methodReturnType);
            //方法体，逻辑代码
            method.addBodyLine("return " + serviceFieldName + ";");
            //修饰符
            method.setVisibility(JavaVisibility.PUBLIC);
            clazz.addImportedType(superServiceInterface);
            clazz.addMethod(method);
        }

        String requestModel = "";
        if (this.isRequestModel) {
            requestModel = "ModelAttribute";
        }
        if (this.isRequestBody) {
            requestModel = "RequestBody";
        }

        Method method;
        if (actionAdd) {
//        @PostMapping("/add")
//        public ResultInfo<Integer> add(@RequestBody SysUser param) {
            method = new Method("add");
            if (!StringUtils.isEmpty(actionRemarkAdd) && !StringUtils.isEmpty(introspectedTable.getRemarks()))
                method.addAnnotation("@ApiOperation(\"" + String.format(actionRemarkAdd, introspectedTable.getRemarks()) + "\")");
            method.addAnnotation("@PostMapping(\"/add\")");
            //method.setAbstract(true);
            method.setVisibility(JavaVisibility.PUBLIC);

            String keyName = null;
            IntrospectedColumn keyColumn = null;
            if (introspectedTable.getPrimaryKeyColumns().size() == 1) {
                keyColumn = introspectedTable.getPrimaryKeyColumns().get(0);
                String kn = String.valueOf(keyColumn.getJavaProperty().charAt(0)).toUpperCase() + keyColumn.getJavaProperty().substring(1);
                keyName = "param.get" + kn + "()";
            }

            if (this.isRequestQuery) {

                method.addBodyLine(modelName + " param = new " + modelName + "();");
                for (IntrospectedColumn column : introspectedTable.getAllColumns()) {
                    if (this.ignoreFieldsToAddSet.contains(column.getActualColumnName())) continue;
                    //
                    String field = column.getJavaProperty();
                    Parameter parameter = new Parameter(column.getFullyQualifiedJavaType(), field);
//                    @ApiParam(name = "ids", value = "..",required = false)
                    parameter.addAnnotation("@ApiParam(name = \"" + field + "\", value = \"" + this.columnRemark(column) + "\", required = false)");
                    parameter.addAnnotation("@RequestParam(\"" + field + "\")");
                    method.addParameter(parameter);
                    //param.setAvatar();
                    String property = String.valueOf(field.charAt(0)).toUpperCase() + field.substring(1);
                    method.addBodyLine("param.set" + property + "(" + field + ");");
                }

            } else {
                if (modelMethods != null) {
                    clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.BeanUtils"));
                    method.addParameter(new Parameter(new FullyQualifiedJavaType(modelMethods[0]), "add", "@" + requestModel));
                    method.addBodyLine(modelName + " param = new " + modelName + "();");
                    method.addBodyLine("BeanUtils.copyProperties(add, param);");
                } else {
                    if (introspectedTable.getPrimaryKeyColumns().size() == 1) {
                        method.addParameter(new Parameter(new FullyQualifiedJavaType(modelName), "param", "@" + requestModel));
                    } else {
                        method.addParameter(new Parameter(new FullyQualifiedJavaType(modelName), "param", "@" + requestModel));
                    }
                }
            }

            for (IntrospectedColumn column : introspectedTable.getAllColumns()) {
                if (this.setDateFieldsToAddSet.contains(column.getActualColumnName())) {
                    String field = column.getJavaProperty();
                    String property = String.valueOf(field.charAt(0)).toUpperCase() + field.substring(1);
                    method.addBodyLine("param.set" + property + "(now);");
                }
            }
            if (this.setDateFieldsToAddSet.size() > 0) {
                method.addBodyLine(0, "java.util.Date now = new java.util.Date();");
            }

            if (introspectedTable.getPrimaryKeyColumns().size() == 1) {
                method.setReturnType(new FullyQualifiedJavaType("ResultInfo<" + keyColumn.getFullyQualifiedJavaType().getShortName() + ">"));
                //method.addBodyLine(new FullyQualifiedJavaType("Integer") + " added = " + serviceFieldName + ".add(param);");
                //method.addBodyLine(new FullyQualifiedJavaType("ResultInfo<" + keyColumn.getFullyQualifiedJavaType().getShortName() + ">") + " info = new ResultInfo<>(" + keyName + ");");
                method.addBodyLine(serviceFieldName + ".add(param);");
                method.addBodyLine("return R.ok(" + keyName + ");");
            } else {
                method.setReturnType(new FullyQualifiedJavaType("ResultInfo<Integer>"));
                method.addBodyLine(new FullyQualifiedJavaType("Integer") + " added = " + serviceFieldName + ".add(param);");
//                method.addBodyLine(new FullyQualifiedJavaType("ResultInfo<Integer>") + " info = new ResultInfo<>(added);");
//                method.addBodyLine("return info;");
                method.addBodyLine("return R.ok(added);");
            }
            clazz.addMethod(method);
        }

        if (actionDel) {
//        @PostMapping("/del")
//        public ResultInfo<Integer> del(@RequestParam("id") Long id) {
            method = new Method("del");
            if (!StringUtils.isEmpty(actionRemarkDel) && !StringUtils.isEmpty(introspectedTable.getRemarks()))
                method.addAnnotation("@ApiOperation(\"" + String.format(actionRemarkDel, introspectedTable.getRemarks()) + "\")");
            method.addAnnotation("@PostMapping(\"/del\")");
            //method.setAbstract(true);
            method.setVisibility(JavaVisibility.PUBLIC);
            method.setReturnType(new FullyQualifiedJavaType("ResultInfo<Integer>"));
            method.addParameter(new Parameter(new FullyQualifiedJavaType("List<" + introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType().getShortName() + ">"), "ids", "@RequestParam(\"ids\")"));
            method.addBodyLine(new FullyQualifiedJavaType("Integer") + " deleted = " + serviceFieldName + ".deleteByIds(ids);");
//            method.addBodyLine(new FullyQualifiedJavaType("ResultInfo<Integer>") + " info = new ResultInfo<>(deleted);");
//            method.addBodyLine("return info;");
            method.addBodyLine("return R.ok(deleted);");
            clazz.addMethod(method);
        }

        if (actionEdit) {
//        @PostMapping("/edit")
//        public ResultInfo<Integer> edit(@RequestBody SysUser param)
            method = new Method("edit");
            if (!StringUtils.isEmpty(actionRemarkEdit) && !StringUtils.isEmpty(introspectedTable.getRemarks()))
                method.addAnnotation("@ApiOperation(\"" + String.format(actionRemarkEdit, introspectedTable.getRemarks()) + "\")");
            method.addAnnotation("@PostMapping(\"/edit\")");
            //method.setAbstract(true);
            method.setVisibility(JavaVisibility.PUBLIC);
            method.setReturnType(new FullyQualifiedJavaType("ResultInfo<Integer>"));

            if (this.isRequestQuery) {
                method.addBodyLine(modelName + " param = new " + modelName + "();");
                for (IntrospectedColumn column : introspectedTable.getAllColumns()) {
                    if (this.ignoreFieldsToEditSet.contains(column.getActualColumnName())) continue;
                    //
                    String field = column.getJavaProperty();
                    Parameter parameter = new Parameter(column.getFullyQualifiedJavaType(), field);
//                    @ApiParam(name = "ids", value = "..",required = false)
                    parameter.addAnnotation("@ApiParam(name=\"" + field + "\", value=\"" + this.columnRemark(column) + "\", required = false)");
                    parameter.addAnnotation("@RequestParam(\"" + field + "\")");
                    method.addParameter(parameter);
                    //param.setAvatar();
                    String property = String.valueOf(field.charAt(0)).toUpperCase() + field.substring(1);
                    method.addBodyLine("param.set" + property + "(" + field + ");");
                }
            } else {
                if (modelMethods != null) {
                    clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.BeanUtils"));
                    method.addParameter(new Parameter(new FullyQualifiedJavaType(modelMethods[1]), "update", "@" + requestModel));
                    method.addBodyLine(modelName + " param = new " + modelName + "();");
                    method.addBodyLine("BeanUtils.copyProperties(update, param);");
                } else {
                    method.addParameter(new Parameter(new FullyQualifiedJavaType(modelName), "param", "@" + requestModel));
                }
            }

            for (IntrospectedColumn column : introspectedTable.getAllColumns()) {
                if (this.setDateFieldsToEditSet.contains(column.getActualColumnName())) {
                    String field = column.getJavaProperty();
                    String property = String.valueOf(field.charAt(0)).toUpperCase() + field.substring(1);
                    method.addBodyLine("param.set" + property + "(now);");
                }
            }
            if (this.setDateFieldsToEditSet.size() > 0) {
                method.addBodyLine(0, "java.util.Date now = new java.util.Date();");
            }

            //
            // updateBody
            if ("yes".equalsIgnoreCase(loadUpdateBodyUse(introspectedTable))) {
                method.addBodyLine(new FullyQualifiedJavaType("Integer") + " updated = " + serviceFieldName + ".updateBody(param);");
            } else {
                method.addBodyLine(new FullyQualifiedJavaType("Integer") + " updated = " + serviceFieldName + ".update(param);");
            }

//            method.addBodyLine(new FullyQualifiedJavaType("ResultInfo<Integer>") + " info = new ResultInfo<>(updated);");
//            method.addBodyLine("return info;");
            method.addBodyLine("return R.ok(updated);");
            clazz.addMethod(method);
        }

        if (actionInfo) {
//        @PostMapping("/{id}")
//        public SysUser info(@RequestParam("id") Long id)
            method = new Method("info");
            //method.addAnnotation("@GetMapping(\"/{id}\")");
            if (!StringUtils.isEmpty(actionRemarkInfo) && !StringUtils.isEmpty(introspectedTable.getRemarks()))
                method.addAnnotation("@ApiOperation(\"" + String.format(actionRemarkInfo, introspectedTable.getRemarks()) + "\")");
            method.addAnnotation("@GetMapping(\"/info\")");
            //method.setAbstract(true);
            method.setVisibility(JavaVisibility.PUBLIC);

            //
            List<IntrospectedColumn> primaryKeyColumns = introspectedTable.getPrimaryKeyColumns();
            if (modelMethods != null && primaryKeyColumns.size() > 0) {
                method.setReturnType(new FullyQualifiedJavaType("ResultInfo<" + new FullyQualifiedJavaType(modelMethods[3]).getShortName() + ">"));
                //
                method.addBodyLine(new FullyQualifiedJavaType(modelMethods[2]).getShortName() + " query = new " + new FullyQualifiedJavaType(modelMethods[2]).getShortName() + "();");
                for (IntrospectedColumn keyColumn : primaryKeyColumns) {
                    String field = keyColumn.getJavaProperty();
                    method.addParameter(new Parameter(keyColumn.getFullyQualifiedJavaType(), field, "@RequestParam(\"" + field + "\")"));
                    String property = String.valueOf(field.charAt(0)).toUpperCase() + field.substring(1);
                    method.addBodyLine("query.set" + property + "(" + field + ");");
                }
                method.addBodyLine(new FullyQualifiedJavaType(modelMethods[3]).getShortName() + " info = " + serviceFieldName + ".listQueryOne(query);");
            } else {
                method.addParameter(new Parameter(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType(), "id", "@RequestParam(\"id\")"));
                method.setReturnType(new FullyQualifiedJavaType("ResultInfo<" + model.getShortName() + ">"));
                method.addBodyLine(new FullyQualifiedJavaType(modelName) + " info = " + serviceFieldName + ".loadById(id);");
            }

            method.addBodyLine("return R.ok(info);");
            clazz.addMethod(method);
        }


        if (pageHelperDisabled) {
            //closed
        } else {
            if (actionList) {
                method = new Method("list");
                if (!StringUtils.isEmpty(actionRemarkList) && !StringUtils.isEmpty(introspectedTable.getRemarks()))
                    method.addAnnotation("@ApiOperation(\"" + String.format(actionRemarkList, introspectedTable.getRemarks()) + "\")");
                method.addAnnotation("@GetMapping(\"/list\")");
                //method.setAbstract(true);
                method.setVisibility(JavaVisibility.PUBLIC);

                if (modelMethods != null) {
                    method.addParameter(new Parameter(new FullyQualifiedJavaType(modelMethods[2]), "param", "@" + requestModel));
                    method.setReturnType(new FullyQualifiedJavaType("ResultList<" + new FullyQualifiedJavaType(modelMethods[3]).getShortName() + ">"));
                    method.addBodyLine(new FullyQualifiedJavaType("PageInfo<" + new FullyQualifiedJavaType(modelMethods[3]).getShortName() + ">") + " info = " + serviceFieldName + ".listQuery(param, pageIndex, pageSize);");
                } else {
                    method.setReturnType(new FullyQualifiedJavaType("ResultList<" + modelName + ">"));
                    method.addParameter(new Parameter(new FullyQualifiedJavaType(modelName), "param"));
                    method.addBodyLine(new FullyQualifiedJavaType("PageInfo<" + modelName + ">") + " info = " + serviceFieldName + ".list(param, pageIndex, pageSize);");
                }

                //
                method.addParameter(new Parameter(new FullyQualifiedJavaType("Integer"), "pageIndex", "@RequestParam(value = \"pageIndex\", defaultValue = \"1\")"));
                method.addParameter(new Parameter(new FullyQualifiedJavaType("Integer"), "pageSize", "@RequestParam(value = \"pageSize\", defaultValue = \"10\")"));

                //
                method.addBodyLine("return L.ok(info);");
                clazz.addMethod(method);
            }

//            if (actionSearch) {
//                method = new Method("search");
//                if (!StringUtils.isEmpty(actionRemarkSearch) && !StringUtils.isEmpty(introspectedTable.getRemarks()))
//                    method.addAnnotation("@ApiOperation(\"" + String.format(actionRemarkSearch, introspectedTable.getRemarks()) + "\")");
//                method.addAnnotation("@GetMapping(\"/search\")");
//                //method.setAbstract(true);
//                method.setVisibility(JavaVisibility.PUBLIC);
//                method.setReturnType(new FullyQualifiedJavaType("ResultList<" + modelName + ">"));
//                method.addParameter(new Parameter(new FullyQualifiedJavaType("Integer"), "pageIndex", "@RequestParam(value = \"pageIndex\", defaultValue = \"1\")"));
//                method.addParameter(new Parameter(new FullyQualifiedJavaType("Integer"), "pageSize", "@RequestParam(value = \"pageSize\", defaultValue = \"10\")"));
//                method.addBodyLine(modelName + " query = new " + modelName + "();");
//                method.addBodyLine(new FullyQualifiedJavaType("PageInfo<" + modelName + ">") + " info = " + serviceFieldName + ".search(query, pageIndex, pageSize);");
//                method.addBodyLine("return new ResultList<>(info);");
//                clazz.addMethod(method);
//            }
        }

        //
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetProject, context.getJavaFormatter());
        return gjf2;
    }

    private String columnRemark(IntrospectedColumn column) {
        String remarks = column.getRemarks();
        if (StringUtils.isEmpty(remarks)) return column.getJavaProperty();
        remarks = remarks.replace("\"", "");
        return remarks;
    }

}
